package io.doge.cc.core;


import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.cache.PathChildrenCache;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent;
import org.apache.curator.retry.RetryNTimes;
import org.apache.zookeeper.data.Stat;

import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

/**
 * Created by number.liu on 2015/10/28
 */
public class ZooDogeCc implements DogeCc {

    private final String appConfigPathRoot = "appConfigPathRoot";
    private String zkAddress;
    private String appName;
    private int timeout;
    private CuratorFramework client;

    public ZooDogeCc(String zkAddress, String appName, int timeout) {
        this.zkAddress = zkAddress;
        this.appName = appName;
        this.timeout = timeout;
        client = CuratorFrameworkFactory.builder()
                .retryPolicy(new RetryNTimes(Integer.MAX_VALUE, 1000))
                .connectionTimeoutMs(timeout)
                .namespace(appConfigPathRoot)
                .connectString(zkAddress).build();
        this.client.start();
        try {
//            Stat stat = this.client.checkExists().forPath("/" + appConfigPathRoot);
//            if (stat == null) this.client.create().forPath("/" + appConfigPathRoot);

            if (!appName.contains("/")) this.appName =  "/" + appName;
             Stat  stat = this.client.checkExists().forPath(this.appName);
            if (stat == null) this.client.create().forPath(this.appName);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }


    @Override
    public Properties getProperties() {
        Properties pts = new Properties();
        try {
            client.getChildren().forPath(appName).forEach(path -> {
                try {
                    byte[] bytes = client.getData().forPath(appName + "/" + path);
                    pts.put(path, new String(bytes));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
        return pts;
    }

    @Override
    public Properties getProperties(String app) {
        Properties pts = new Properties();
        app = "/"+app;
        try {
            final String finalApp = app;
            client.getChildren().forPath(app).forEach(path -> {
                try {
                    byte[] bytes = client.getData().forPath(finalApp + "/" + path);
                    pts.put(path, new String(bytes));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
        return pts;
    }

    @Override
    public void setProperties(Properties properties) {
        properties.entrySet().forEach(entry -> this.add((String) entry.getKey(), (String) entry.getValue()));
    }

    @Override
    public void add(String key, String value) {
        try {
            String child = appName + "/" + key;
            if (client.checkExists().forPath(child) == null) {
                client.create().forPath(child, value.getBytes());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void delete(String key) {
        try {
            this.client.delete().forPath(appName + "/" + key);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    @Override
    public void onChanged(PropertiesChangedCallback properties) {
        new PathChildrenCache(this.client, appName, true).getListenable().addListener((CuratorFramework client, PathChildrenCacheEvent event) -> {
            properties.onChanged(getProperties());
        });
    }

    @Override
    public void close() {
        this.client.close();
    }

    @Override
    public List<String> getChildren(String parent) {
        try {
            return client.getChildren().forPath(parent);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return new ArrayList<String>();
    }

    @Override
    public List<String> getChildren() {
        try {
            return this.client.getZookeeperClient().getZooKeeper().getChildren("/" + appConfigPathRoot, false);
            //            return client.getChildren().forPath();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return new ArrayList<String>();
    }

    @Override
    public String get(String key) {
        try {
           return new String(this.client.getData().forPath(appName + "/" + key));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return new String();
    }

    @Override
    public void update(String key, String value) {
        try {
            String child = appName + "/" + key;
            if (client.checkExists().forPath(child) == null) {
                client.create().forPath(child, value.getBytes());
            }else{
                client.setData().forPath(child,value.getBytes());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
